package com.core.aspect;


import com.app.utils.JsonUtil;
import com.app.utils.ShiroUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sys.log.entity.SysLog;
import com.sys.log.service.SysLogService;
import com.sys.user.entity.SysUser;
import com.utils.DateFormatUtil;

import java.io.BufferedReader;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import lombok.extern.slf4j.Slf4j;

/**
 * Web层日志切面
 */
//增强类
@Aspect
@Order(5)
@Component
@Slf4j
public class WebLogAspect{

	@Autowired
	SysLogService sysLogService;
	
	ThreadLocal<Long> startTime = new ThreadLocal<>();
	
	@Pointcut("execution(public *  com..controller..*.*(..))")
	public void webLog(){}
	
	
	/**
	 * 访问前  环绕通知
	 * @param joinPoint
	 * @throws Throwable
	 */
	@Before("webLog()")
	public void doBefore(JoinPoint joinPoint) throws Throwable {
		startTime.set(System.currentTimeMillis());
		 
        // 接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
 
        
        // 记录下请求内容
//      log.info("请求路径 : " + request.getRequestURL().toString());
        log.info("请求方法 : " + request.getMethod());
        log.info("请求ip " + request.getRemoteAddr());
        log.info("访问控制层 : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        log.info("参数 : " + Arrays.toString(joinPoint.getArgs()));
        
        try
        {
          Signature signature = joinPoint.getSignature();
          MethodSignature methodSignature = (MethodSignature)signature;
          Method targetMethod = methodSignature.getMethod();
          Method realMethod = joinPoint.getTarget().getClass().getDeclaredMethod(signature.getName(), targetMethod.getParameterTypes());
          Log log = (Log)realMethod.getAnnotation(Log.class);
          if (log == null) {
            return;
          }
          System.out.println(log.value());
  		  saveLog(request,joinPoint,log);
          
        }
        catch (Exception e)
        {
          e.printStackTrace();
        }

        
	}
	
	/**
	 * 访问处理
	 * @param ret
	 * @throws Throwable
	 */
 	@AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 处理完请求，返回内容
	 log.info("请求结束 : " + ret);
	 log.info("耗时 : " + (System.currentTimeMillis() - startTime.get()));
    }

 	/**
 	 * 发生错误
 	 * @param ret
 	 * @throws Throwable
 	 */
 	@AfterThrowing(pointcut = "webLog()",throwing="ret")
 	public void dofterThrowing(Object ret) throws Throwable {
        // 处理完请求，返回内容
	 log.info("发生错误 : " + ret);
	 log.info("耗时 : " + (System.currentTimeMillis() - startTime.get()));
    }
 	
 	
 	public void saveLog(HttpServletRequest request, JoinPoint joinPoint, Log logValue) {
 		SysLog sysLog = new SysLog();
 		String urlString = request.getRequestURI();
		String url = urlString.substring(0, urlString.indexOf("?") == -1 ? urlString.length() : urlString.indexOf("?"));
		if("/login.do".equals(url)) {
			sysLog.setUserName("游客");
			sysLog.setUserType("99");
		}else {
			SysUser me = ShiroUtil.getSessionUser();
			if(me!=null) {
				sysLog.setUserId(me.getId());
		        sysLog.setUserName(me.getUserName());
		        sysLog.setUserType(me.getUserType());
			}
		}
        
        sysLog.setUrl(request.getRequestURI());
        Map<String, Object> strMap = new HashMap<String, Object>();
        try
        {
          Object[] objects = joinPoint.getArgs();
          Map<String, Object> map;
          for (int i = 0; i < objects.length; i++) {
            if ((!(objects[i] instanceof ShiroHttpServletRequest)) && (!(objects[i] instanceof ServletResponse)) && (!(objects[i] instanceof ServletRequest)) && (!(objects[i] instanceof Page)))
            {
              map = JsonUtil.formatToMap(JsonUtil.formatToStr(objects[i]));
              for (String key : map.keySet())
              {
                Object value = map.get(key);
                if (value != null) {
                  strMap.put(key, value);
                }
              }
            }
          }
        }
        catch (Exception e)
        {
        	log.info("转换出错:"+e);
//          e.printStackTrace();
        }
        sysLog.setParams(JsonUtil.formatToStr(strMap));
        sysLog.setTitle(logValue.value());
        sysLog.setIp(getClientIP(request));
        sysLog.setClientInfo(getClientInfo(request));
        sysLog.setClassMethod(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        sysLog.setMethod(request.getMethod());
        sysLog.setHost(request.getRemoteHost());
        sysLog.setCreateTime(DateFormatUtil.getStringDateYMDHMS());
        this.sysLogService.insert(sysLog);
 	}
 	

 	
 	public static String getClientIP(HttpServletRequest request)
 	  {
 	    String ip = request.getHeader("x-forwarded-for");
 	    if ((ip == null) || (ip.length() == 0) || ("unknown".equalsIgnoreCase(ip))) {
 	      ip = request.getHeader("Proxy-Client-IP");
 	    }
 	    if ((ip == null) || (ip.length() == 0) || ("unknown".equalsIgnoreCase(ip))) {
 	      ip = request.getHeader("WL-Proxy-Client-IP");
 	    }
 	    if ((ip == null) || (ip.length() == 0) || ("unknown".equalsIgnoreCase(ip))) {
 	      ip = request.getRemoteAddr();
 	    }
 	    if (("0:0:0:0:0:0:0:1".equals(ip)) || ("127.0.0.1".equals(ip))) {
 	      try
 	      {
 	        ip = InetAddress.getLocalHost().getHostAddress();
 	      }
 	      catch (UnknownHostException var3)
 	      {
 	        ip = "127.0.0.1";
 	      }
 	    }
 	    if ((ip != null) && (ip.length() > 15) && (ip.indexOf(",") > 0)) {
 	      ip = ip.substring(0, ip.indexOf(","));
 	    }
 	    return ip;
 	  }
 	
 	
 	
 	 
 	 /**
 	  * web端获取数据
 	  * @param request
 	  * @return
 	  */
 	 private String getClientInfo(HttpServletRequest request) {
 	    Map map = new HashMap();
 	    map.put("浏览器基本信息：", request.getHeader("user-agent"));
 	    map.put("<br/>客户端系统名称：", System.getProperty("os.name"));
 	    map.put("<br/>客户端系统版本：", System.getProperty("os.version"));
 	    map.put("<br/>客户端操作系统位数：", System.getProperty("os.arch"));
 	    map.put("<br/>HTTP协议版本：", request.getProtocol());
 	    map.put("<br/>请求编码格式：", request.getCharacterEncoding());
 	    map.put("<br/>Accept：", request.getHeader("Accept"));
 	    map.put("<br/>Accept-语言：", request.getHeader("Accept-Language"));
 	    map.put("<br/>Accept-编码：", request.getHeader("Accept-Encoding"));
 	    map.put("<br/>Connection：", request.getHeader("Connection"));
 	    map.put("<br/>Cookie：", request.getHeader("Cookie"));
 	    map.put("<br/>客户端发出请求时的完整URL", request.getRequestURL());
 	    map.put("<br/>请求行中的资源名部分", request.getRequestURI());
 	    map.put("<br/>请求行中的参数部分", request.getRemoteAddr());
 	    map.put("<br/>客户机所使用的网络端口号", Integer.valueOf(request.getRemotePort()));
 	    map.put("<br/>WEB服务器的IP地址", request.getLocalAddr());
 	    map.put("<br/>WEB服务器的主机名", request.getLocalName());
 	    map.put("<br/>客户机请求方式", request.getMethod());
 	    map.put("<br/>请求的文件的路径", request.getServerName());
 	    try
 	    {
 	      log.info("浏览器基本信息：" + request.getHeader("user-agent"));
 	      log.info("客户端系统名称：" + System.getProperty("os.name"));
 	      log.info("客户端系统版本：" + System.getProperty("os.version"));
 	      log.info("客户端操作系统位数：" + System.getProperty("os.arch"));
 	      log.info("HTTP协议版本：" + request.getProtocol());
 	      log.info("请求编码格式：" + request.getCharacterEncoding());
 	      log.info("Accept：" + request.getHeader("Accept"));
 	      log.info("Accept-语言：" + request.getHeader("Accept-Language"));
 	      log.info("Accept-编码：" + request.getHeader("Accept-Encoding"));
 	      log.info("Connection：" + request.getHeader("Connection"));
 	      log.info("Cookie：" + request.getHeader("Cookie"));
 	      log.info("客户端发出请求时的完整URL" + request.getRequestURL());
 	      log.info("请求行中的资源名部分" + request.getRequestURI());
 	      log.info("请求行中的参数部分" + request.getRemoteAddr());
 	      log.info("客户机所使用的网络端口号" + request.getRemotePort());
 	      log.info("WEB服务器的IP地址" + request.getLocalAddr());
 	      log.info("WEB服务器的主机名" + request.getLocalName());
 	      log.info("客户机请求方式" + request.getMethod());
 	      log.info("请求的文件的路径" + request.getServerName());
 	      log.info("请求体的数据流" + request.getReader());
 	      BufferedReader br = request.getReader();
 	      String res = "";
 	      while ((res = br.readLine()) != null) {
 	        log.info("request body:" + res);
 	      }
 	      log.info("请求所使用的协议名称" + request.getProtocol());
 	      log.info("请求中所有参数的名字" + request.getParameterNames());
 	      Enumeration enumNames = request.getParameterNames();
 	      while (enumNames.hasMoreElements())
 	      {
 	        String key = (String)enumNames.nextElement();
 	        log.info("参数名称：" + key);
 	      }
 	    }
 	    catch (Exception e)
 	    {
 	      e.printStackTrace();
 	    }
 	    return JsonUtil.formatToStr(map);
 	  }

 	
 	
}
